package pl.elka.simulator.mediator;

import java.util.ArrayList;
import java.util.List;

import pl.elka.simulator.core.IPaintable;
import pl.elka.simulator.core.Position;
import pl.elka.simulator.core.Simulator;
import pl.elka.simulator.core.configurationCommand.ConfigurationCommandFactory;
import pl.elka.simulator.core.configurationCommand.ConfigurationCommandType;
import pl.elka.simulator.core.configurationCommand.ICommandParam;
import pl.elka.simulator.core.configurationCommand.ICommandParamConstructor;
import pl.elka.simulator.core.configurationCommand.IConfigurationCommand;
import pl.elka.simulator.core.mobilityManager.IMobilityManager;
import pl.elka.simulator.core.mobilityManager.MobilityManagerFactory;
import pl.elka.simulator.core.mobilityManager.MobilityManagerType;

public class SimulationFasade implements ISimulationFasade {
	
	private static SimulationFasade instance = new SimulationFasade();
	private Simulator simulator = new Simulator();
	private ICommandParamConstructor paramConstructor;
	private ConfigurationCommandType selectedCommandType;
	private String mobilityManagerId;
	
	private SimulationFasade(){};
	
	public static SimulationFasade getInstance(){
		return instance;
	}
	
	@Override
	public ActionResult handleAction(ActionType type, ActionValue value){
		
		switch (type) {
			case AddMobilityManager:
				addMobilityManager(value);
				break;
			case GetAllowedConfigurationCommands:
				return getAllowedConfigurationCommands(value);	
			case GetAllowedEnviromentConfigurationCommand:
				return getAllowedConfigurationCommands(new ActionValue(Simulator.enviromentConfigurationId));	
			case BeginConfigurationParamCreation:
				beginConfigurationCommandCreation(value);
				break;
			case PositionSelected:
				positionSelected(value);
				break;
			case GetVisibleElements:
				return getVisibleElements();
			case RunSimulation:
				runSimulation(value);
				break;
			default:
				break;
		}
		
		return null;
	}

	private void runSimulation(ActionValue value) {
		String id = (String)value.getValue();
		simulator.runSimulation(id);
	}

	private ActionResult getVisibleElements() {
		List<IPaintable> visible = new ArrayList<IPaintable>();
		visible.addAll(simulator.getPaintableElements());
		if(paramConstructor!=null && paramConstructor.getVisibleParts()!=null){
			visible.add(paramConstructor.getVisibleParts());
		}
		return new ActionResult(visible);
	}

	private void positionSelected(ActionValue value) {
		Position position = (Position)value.getValue();				
		if(paramConstructor != null && selectedCommandType != null){
			paramConstructor.appendPart(ICommandParamConstructor.POSITION, position);
			if(paramConstructor.isParamConstruced()){
				ICommandParam param = paramConstructor.getParam();
				IConfigurationCommand cmd = ConfigurationCommandFactory.getInstance().getCommandByType(selectedCommandType);
				cmd.setParam(param);
				simulator.executeConfigurationCommand(cmd, mobilityManagerId);
				paramConstructor = paramConstructor.newInstance();
			}
		}
	}
		

	private void beginConfigurationCommandCreation(ActionValue value) {
		ConfigurationCommandType ccType = (ConfigurationCommandType)((Object[])value.getValue())[0];
		mobilityManagerId = (String)((Object[])value.getValue())[1];
		paramConstructor = ConfigurationCommandFactory.getInstance().getConstructorByType(ccType);
		selectedCommandType = ccType;
	}

	private ActionResult getAllowedConfigurationCommands(ActionValue value) {
		String id = (String)value.getValue();
		List<ConfigurationCommandType> types = simulator.getAllowedConfigurationCommands(id);
		return new ActionResult(types);
	}

	private void addMobilityManager(ActionValue value) {
		MobilityManagerType mmType = (MobilityManagerType)((Object[])value.getValue())[0];
		String id = (String)((Object[])value.getValue())[1];
		IMobilityManager manager = MobilityManagerFactory.getInstance().getMobilityManagerByType(mmType);
		manager.setId(id);
		simulator.addMobilityManager(manager);
	}

	public Simulator getSimulator() {
		return simulator;
	}
	public void setSimulator(Simulator simulator){
		this.simulator = simulator;
	}
}
